package com.bsj.power.system.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResult;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.global.TokenUser;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.menu.MenuDTO;
import com.bsj.power.common.def.dto.menu.MenuSearchDTO;
import com.bsj.power.common.def.entity.menu.Menu;
import com.bsj.power.common.def.entity.menu.RoleMenu;
import com.bsj.power.common.def.entity.role.Role;
import com.bsj.power.common.def.entity.user.User;
import com.bsj.power.common.def.vo.sys.menu.MenuTreeVO;
import com.bsj.power.common.def.vo.sys.menu.MenuVO;
import com.bsj.power.common.mapper.MenuMapper;
import com.bsj.power.common.mapper.RoleMapper;
import com.bsj.power.common.mapper.RoleMenuMapper;
import com.bsj.power.common.mapper.UserMapper;
import com.bsj.power.common.util.ParamCheckUtil;
import com.bsj.power.common.util.StpLoginUserUtil;
import com.bsj.power.system.service.MenuService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/***
 * @description MenuServiceImpl
 * @author LiJiaXin
 * @version 1.0.0
 * @time 2024/1/12 16:36
 **/
@Service
public class MenuServiceImpl implements MenuService {

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private UserMapper userMapper;

//    @Autowired
//    private TokenService tokenService;

    private static final List<String> HIDE_MENU_SIGN_LIST = List.of("/master/system/menu", "/master/system/role", "/master/system/user", "/master/system/systemOpLog");

    /**
     * 添加权限
     *
     * @param menuDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/11 12:06
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult addMenu(MenuDTO menuDTO) {
        paramCheck(menuDTO);
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        if (menuMapper.insert(menu) > NumericalConstants.ZERO) {
            //绑定admin账号
            Long roleId = roleMapper.selectOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleSign, "SUPER_ADMIN")).getRoleId();
            if (roleMenuMapper.insert(new RoleMenu(roleId, menu.getMenuId())) > NumericalConstants.ZERO) {
                return JsonResult.success();
            } else {
                return JsonResult.fail();
            }
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 参数校验
     *
     * @param menuDTO
     * @return void
     * @author ljx
     * @time 2024/9/11 12:08
     */
    private void paramCheck(MenuDTO menuDTO) {
        authCheck();
        //去重校验
        MenuSearchDTO menuSearchDTO = new MenuSearchDTO();
        menuSearchDTO.setMenuId(menuDTO.getMenuId());
//        menuSearchDTO.setMenuName(menuDTO.getMenuName());
//        if (menuMapper.countByCondition(menuSearchDTO) >= 1) {
//            throw new ApiException(JsonResultEnum.MENU_NAME_IS_NOT_NULL);
//        }
//        menuSearchDTO.setMenuName(null);
        menuSearchDTO.setMenuSign(menuDTO.getMenuSign());
        if (menuMapper.countByCondition(menuSearchDTO) > NumericalConstants.ZERO) {
            throw new ApiException(JsonResultEnum.MENU_SIGN_IS_NOT_NULL);
        }
    }

    /**
     * 删除权限
     *
     * @param menuId
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/11 12:06
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult deleteMenu(Integer menuId) {
        authCheck();
        ParamCheckUtil.isNull(menuId);
        ParamCheckUtil.isNull(menuMapper.selectById(menuId), JsonResultEnum.MENU_IS_NOT_EXIST);
        if (roleMenuMapper.exists(new QueryWrapper<RoleMenu>().lambda().eq(RoleMenu::getMenuId, menuId))) {
            return JsonResult.fail(JsonResultEnum.FAIL, "此权限与某角色已绑定，无法删除");
        }
        if (menuMapper.deleteById(menuId) > NumericalConstants.ZERO) {
//            //删除与角色的关系
            roleMenuMapper.delete(new QueryWrapper<RoleMenu>().eq("menu_id", menuId));
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 权限校验
     *
     * @return void
     * @author ljx
     * @time 2024/9/13 17:29
     */
    private void authCheck() {
        TokenUser tokenUser = StpLoginUserUtil.getTokenUser();
        Long loginUserId = tokenUser.getUserId();
        User user = userMapper.selectById(loginUserId);
        if (user.getParentId() != -1) {
            throw new ApiException(JsonResultEnum.USER_IS_NOT_ADMIN_UN_OPERATE);
        }
    }

    /**
     * 修改权限
     *
     * @param menuDTO
     * @return com.bsj.power.common.config.global.JsonResult
     * @author ljx
     * @time 2024/9/11 12:06
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult updateMenu(MenuDTO menuDTO) {
        Integer menuId = menuDTO.getMenuId();
        ParamCheckUtil.isNull(menuId);
        ParamCheckUtil.isNull(menuMapper.selectById(menuId), JsonResultEnum.MENU_IS_NOT_EXIST);
        paramCheck(menuDTO);
        Menu menu = new Menu();
        BeanUtils.copyProperties(menuDTO, menu);
        if (menuMapper.updateById(menu) > NumericalConstants.ZERO) {
            return JsonResult.success();
        } else {
            return JsonResult.fail();
        }
    }

    /**
     * 根据权限id获取权限信息
     *
     * @param menuId
     * @return com.bsj.power.common.def.vo.sys.menu.MenuVO
     * @author ljx
     * @time 2024/9/11 12:06
     */
    @Override
    public MenuVO getMenuInfoById(Integer menuId) {
        ParamCheckUtil.isNull(menuId);
        Menu menu = menuMapper.selectById(menuId);
        ParamCheckUtil.isNull(menu, JsonResultEnum.MENU_IS_NOT_EXIST);
        MenuVO menuVO = new MenuVO();
        BeanUtils.copyProperties(menu, menuVO);
        return menuVO;
    }

    /**
     * 权限分页
     *
     * @param menuSearchDTO
     * @return com.bsj.power.common.config.global.JsonResult<java.util.List < com.bsj.power.common.def.vo.sys.menu.MenuVO>>
     * @author ljx
     * @time 2024/9/11 12:07
     */
    @Override
    public JsonResult<List<MenuVO>> pageMenu(MenuSearchDTO menuSearchDTO) {
        IPage<Menu> page = new Page<>(menuSearchDTO.getPageNumber(), menuSearchDTO.getPageSize());
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        String menuName = menuSearchDTO.getMenuName();
        String menuSign = menuSearchDTO.getMenuSign();
        if (StringUtils.isNotBlank(menuName)) {
            queryWrapper.like("menu_name", menuName);
        }
        if (StringUtils.isNotBlank(menuSign)) {
            queryWrapper.like("menu_sign", menuSign);
        }
        IPage<Menu> iPage = menuMapper.selectPage(page, queryWrapper);
        List<Menu> menuDOS = iPage.getRecords();
        int total = (int) iPage.getTotal();
        List<MenuVO> menuVOS = new LinkedList<>();
        if (total == 0) {
            return JsonResult.success(menuVOS, total);
        }
        menuVOS = menuDOS.stream().map(menuDO -> {
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(menuDO, menuVO);
            menuVO.setCreateTime(DateUtil.formatDateTime(menuDO.getCreateTime()));
            menuVO.setUpdateTime(DateUtil.formatDateTime(menuDO.getUpdateTime()));
            return menuVO;
        }).collect(Collectors.toList());
        return JsonResult.success(menuVOS, total);
    }

    /**
     * 获取权限树
     *
     * @return java.util.List<com.bsj.power.common.def.vo.sys.menu.MenuTreeVO>
     * @author ljx
     * @time 2024/9/11 12:07
     */
    @Override
    public List<MenuTreeVO> getMenuTree() {
        List<MenuTreeVO> menuTreeVOS = new ArrayList<>();
        TokenUser tokenUser = StpLoginUserUtil.getTokenUser();
        String roleSign = tokenUser.getRoleSign();
        Role role = roleMapper.selectOne(Wrappers.<Role>lambdaQuery().eq(Role::getRoleSign, roleSign));
        if (role != null) {
            List<RoleMenu> roleMenus = roleMenuMapper.selectList(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, role.getRoleId()));
            if (!CollectionUtils.isEmpty(roleMenus)) {
                List<Integer> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(menuIds)) {
                    List<Menu> menus = menuMapper.selectList(Wrappers.<Menu>lambdaQuery().in(Menu::getMenuId, menuIds));
                    menuTreeVOS = structureErection(menus);
                }
            }
        }
        return menuTreeVOS;
    }

    /**
     * 树结构搭建
     *
     * @param menus
     * @return java.util.List<com.bsj.power.common.def.vo.sys.menu.MenuTreeVO>
     * @author ljx
     * @time 2024/9/11 12:07
     */
    @Override
    public List<MenuTreeVO> structureErection(List<Menu> menus) {
        List<MenuTreeVO> menuTreeVOS = new LinkedList<>();
        if (CollectionUtils.isEmpty(menus)) {
            return menuTreeVOS;
        }
        //先排序
        List<Menu> parentMenus = menus.stream().filter(menu -> menu.getParentId().equals(NumericalConstants.NEGATIVE_ONE))
                .sorted(Comparator.comparing(Menu::getSerialNo)).collect(Collectors.toList());
        List<Menu> sonMenus = menus.stream().filter(menu -> !menu.getParentId().equals(NumericalConstants.NEGATIVE_ONE))
                .sorted(Comparator.comparing(Menu::getSerialNo)).collect(Collectors.toList());
        List<Menu> menuList = new LinkedList<>(parentMenus);
        menuList.addAll(sonMenus);
        //类型转换
        Map<Integer, MenuTreeVO> menuTreeVOMap = menuList.stream().map(menu -> {
            MenuTreeVO tree = new MenuTreeVO();
            BeanUtils.copyProperties(menu, tree);
            return tree;
        }).collect(Collectors.toMap(MenuTreeVO::getMenuId, a -> a, (k1, k2) -> k1));

        for (Menu menu : menuList) {
            //当前权限
            MenuTreeVO tree = menuTreeVOMap.get(menu.getMenuId());
            //用户、角色、权限、数据记录与审计四个模块不显示在树结构中
            if (HIDE_MENU_SIGN_LIST.contains(tree.getMenuSign())) {
                continue;
            }
            //当前权限的父权限
            MenuTreeVO parentMenuTree = menuTreeVOMap.get(menu.getParentId());
            //不为空说明有上级权限
            if (parentMenuTree != null) {
                List<MenuTreeVO> children = parentMenuTree.getChildren();
                if (CollectionUtils.isEmpty(children)) {
                    List<MenuTreeVO> menuTreeVOList = new LinkedList<>();
                    menuTreeVOList.add(tree);
                    parentMenuTree.setChildren(menuTreeVOList);
                } else {
                    children.add(tree);
                }
            } else {
                //最上层权限
                menuTreeVOS.add(tree);
            }
        }
        return menuTreeVOS;
    }
}
